package com.member.shop.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.member.common.enums.GrantResultEnum;
import com.member.common.utils.DateUtils;
import com.member.common.utils.bean.BeanUtils;
import com.member.shop.domain.*;
import com.member.shop.mapper.*;
import com.member.shop.service.ISysBizCouponGoodsUserService;
import com.member.shop.service.ISysBizCouponGrantService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * 优惠券发放Service业务层处理
 *
 * @author lixinchen
 * @date 2024-05-08
 */
@Service
public class SysBizCouponGrantServiceImpl extends ServiceImpl<SysBizCouponGrantMapper, SysBizCouponGrant> implements ISysBizCouponGrantService {
    @Resource
    private SysBizCouponGrantMapper sysBizCouponGrantMapper;
    @Resource
    private SysBizCouponMapper sysBizCouponMapper;

    @Resource
    private SysBizUserMapper sysBizUserMapper;

    @Resource
    private SysBizCouponGrantUserMapper sysBizCouponGrantUserMapper;

    @Resource
    private SysBizCouponReceiveMapper sysBizCouponReceiveMapper;

    @Resource
    private SysBizCouponGoodsMapper sysBizCouponGoodsMapper;


    @Resource
    private ISysBizCouponGoodsUserService sysBizCouponGoodsUserService;

    /**
     * 查询优惠券发放
     *
     * @param id 优惠券发放主键
     * @return 优惠券发放
     */
    @Override
    public SysBizCouponGrant selectSysBizCouponGrantById(Long id) {
        return sysBizCouponGrantMapper.selectById(id);
    }

    /**
     * 查询优惠券发放列表
     *
     * @param queryWrapper 优惠券发放
     * @return 优惠券发放
     */
    @Override
    public List<SysBizCouponGrant> selectSysBizCouponGrantList(LambdaQueryWrapper<SysBizCouponGrant> queryWrapper) {
        return sysBizCouponGrantMapper.selectList(queryWrapper);
    }

    @Override
    public List<SysBizCouponGrant> selectSysBizCouponGrantList(SysBizCouponGrant sysBizCouponGrant) {
        return sysBizCouponGrantMapper.selectSysBizCouponGrantList(sysBizCouponGrant);
    }


    private final ReentrantLock lock = new ReentrantLock();

    /**
     * 新增优惠券发放
     *
     * @param sysBizCouponGrant 优惠券发放
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertSysBizCouponGrant(SysBizCouponGrant sysBizCouponGrant) throws Exception {
        // 优化1: 并发控制 - 使用更细粒度的锁或优化锁策略
        // 假设lock是已经定义好的ReentrantLock实例
        lock.lock();
        try {
            // 查询优惠券信息
            SysBizCoupon sysBizCoupon = sysBizCouponMapper.selectSysBizCouponById(sysBizCouponGrant.getCouponId());
            // 查询优惠券的商品
            List<SysBizCouponGoods> sysBizCouponGoodsList = getCouponGoodsByCouponId(sysBizCoupon.getId());

            // 复制查询到的优惠券信息到grant对象中
            BeanUtils.copyProperties(sysBizCoupon, sysBizCouponGrant);
            // 设置创建时间和发放时间
            sysBizCouponGrant.setId(null);
            sysBizCouponGrant.setCreateTime(DateUtils.getNowDate());
            sysBizCouponGrant.setGrantTime(DateUtils.getNowDate());
            // 插入优惠券发放记录
            int insert = sysBizCouponGrantMapper.insert(sysBizCouponGrant);

            // 如果存在用户手机号列表，则为每个手机号创建发放记录
            if (!sysBizCouponGrant.getUserPhoneList().isEmpty()) {
                for (String userPhone : sysBizCouponGrant.getUserPhoneList()) {
                    // 分发优惠券给用户
                    distributeCouponToUser(sysBizCoupon, sysBizCouponGrant, userPhone, sysBizCouponGoodsList);
                }
            }
            return insert;
        } finally {
            lock.unlock();
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public int SysBizCouponGrantByUser(List<SysBizCoupon> sysBizCoupons,String userPhone) throws Exception {
        // 优化1: 并发控制 - 使用更细粒度的锁或优化锁策略
        // 假设lock是已经定义好的ReentrantLock实例
        lock.lock();
        try {
            for (SysBizCoupon coupon : sysBizCoupons) {
                // 查询优惠券信息
                SysBizCoupon sysBizCoupon = sysBizCouponMapper.selectSysBizCouponById(coupon.getId());
                // 查询优惠券的商品
                List<SysBizCouponGoods> sysBizCouponGoodsList = getCouponGoodsByCouponId(sysBizCoupon.getId());

                SysBizCouponGrant sysBizCouponGrant = new SysBizCouponGrant();
                // 复制查询到的优惠券信息到grant对象中
                BeanUtils.copyProperties(sysBizCoupon, sysBizCouponGrant);
                // 设置创建时间和发放时间
                sysBizCouponGrant.setGrantNum(coupon.getLimitNumber());
                sysBizCouponGrant.setId(null);
                sysBizCouponGrant.setCouponId(sysBizCoupon.getId());
                sysBizCouponGrant.setCreateTime(DateUtils.getNowDate());
                sysBizCouponGrant.setGrantTime(DateUtils.getNowDate());
                // 插入优惠券发放记录
                int insert = sysBizCouponGrantMapper.insert(sysBizCouponGrant);
                // 分发优惠券给用户
                distributeCouponToUser(sysBizCoupon, sysBizCouponGrant, userPhone, sysBizCouponGoodsList);
            }
            return 1;
        } finally {
            lock.unlock();
        }
    }

    private List<SysBizCouponGoods> getCouponGoodsByCouponId(Long couponId) {
        LambdaQueryWrapper<SysBizCouponGoods> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysBizCouponGoods::getCouponId, couponId);
        return sysBizCouponGoodsMapper.selectList(queryWrapper);
    }

    private void distributeCouponToUser(SysBizCoupon sysBizCoupon, SysBizCouponGrant sysBizCouponGrant, String userPhone, List<SysBizCouponGoods> sysBizCouponGoodsList) throws Exception {
        // 查询用户信息
        List<SysBizUser> sysBizUsers = sysBizUserMapper.selectList(new LambdaQueryWrapper<>(SysBizUser.class).eq(SysBizUser::getUserPhone, userPhone));

        for (int i = 0; i < sysBizCouponGrant.getGrantNum(); i++) {
            SysBizCouponGrantUser sysBizCouponGrantUser = new SysBizCouponGrantUser();
            sysBizCouponGrantUser.setGrantId(sysBizCouponGrant.getId());
            sysBizCouponGrantUser.setPhone(userPhone);
            sysBizCouponGrantUser.setGrantTime(DateUtils.getNowDate());

            // 检查优惠券剩余数量
            if (sysBizCoupon.getSurplusNum() <= 0) {
                sysBizCouponGrantUser.setFailReason("优惠券数量不足");
                sysBizCouponGrantUser.setGrantResult(GrantResultEnum.FAIL.getKey());
                sysBizCouponGrantUserMapper.insert(sysBizCouponGrantUser);
                continue;
            }

            // 获取用户信息，这里假设第一个匹配的用户即为有效用户
            SysBizUser sysBizUser = !sysBizUsers.isEmpty() ? sysBizUsers.get(0) : null;

            // 检查用户是否存在
            if (sysBizUser == null) {
                sysBizCouponGrantUser.setGrantResult(GrantResultEnum.FAIL.getKey());
                sysBizCouponGrantUser.setFailReason("未查询到该手机号用户");
                sysBizCouponGrantUserMapper.insert(sysBizCouponGrantUser);
                continue;
            }

            if (!sysBizUser.getTenantId().equals(sysBizCoupon.getTenantId())) {
                sysBizCouponGrantUser.setGrantResult(GrantResultEnum.FAIL.getKey());
                sysBizCouponGrantUser.setFailReason("该用户站点和优惠券站点不统一");
                sysBizCouponGrantUser.setUserName(sysBizUser.getNickName());
                sysBizCouponGrantUserMapper.insert(sysBizCouponGrantUser);
                continue;
            }

            //判断该优惠券是否是新人优惠券
            if(sysBizCoupon.getNewCoupon()==1){
                // 查询该用户是否领取过新人优惠券
                List<SysBizCouponReceive> sysBizCouponReceives = sysBizCouponReceiveMapper.selectList(new LambdaQueryWrapper<SysBizCouponReceive>()
                        .eq(SysBizCouponReceive::getPhone, userPhone)
                        .eq(SysBizCouponReceive::getNewCoupon, 1));
                if (!CollectionUtils.isEmpty(sysBizCouponReceives) && sysBizCouponReceives.size()>=3) {
                    sysBizCouponGrantUser.setGrantResult(GrantResultEnum.FAIL.getKey());
                    sysBizCouponGrantUser.setFailReason("该用户已领取新人优惠券");
                    sysBizCouponGrantUser.setUserName(sysBizUser.getNickName());
                    sysBizCouponGrantUserMapper.insert(sysBizCouponGrantUser);
                    continue;
                }
                sysBizCouponGrantUser.setGrantResult(GrantResultEnum.SUCCESS.getKey());
            }


            // 用户领取限制逻辑（示例中未实现具体的限制逻辑，需根据业务需求添加）
            // 假设checkUserLimit返回true表示可以继续发放，false表示达到领取上限
            if (!checkUserLimit(sysBizUser.getId(), sysBizCoupon.getId())) {
                sysBizCouponGrantUser.setGrantResult(GrantResultEnum.FAIL.getKey());
                sysBizCouponGrantUser.setFailReason("该用户已达到领取上限制");
                sysBizCouponGrantUserMapper.insert(sysBizCouponGrantUser);
                continue;
            }

            // 更新优惠券发放状态（使用事务保证数据一致性）
            SysBizCouponReceive sysBizCouponReceive = updateCouponAndInsertReceiveRecord(sysBizCoupon, sysBizUser, null, sysBizCouponGrant);

            // 设置发放成功
            sysBizCouponGrantUser.setGrantResult(GrantResultEnum.SUCCESS.getKey());
            sysBizCouponGrantUser.setUserName(sysBizUser.getNickName());
            sysBizCouponGrantUserMapper.insert(sysBizCouponGrantUser);


            insertCouponGoodsUserRecords(sysBizUser, sysBizCouponReceive.getId(), sysBizCouponGoodsList);

        }
    }

    private boolean checkUserLimit(Long userId, Long couponId) {
        // 实现用户领取优惠券的限制检查逻辑，例如查询用户领取该优惠券的数量是否达到上限
        // 返回true表示可以继续发放，false表示达到领取上限
        // 示例代码，实际逻辑需根据业务需求编写
        return true;
    }

    private SysBizCouponReceive updateCouponAndInsertReceiveRecord(SysBizCoupon sysBizCoupon, SysBizUser sysBizUser, SysBizCouponReceive sysBizCouponReceive, SysBizCouponGrant sysBizCouponGrant) throws Exception {
        // 使用事务处理优惠券的发放和记录插入

        if (sysBizCoupon.getSurplusNum() <= 0) {
            throw new Exception("优惠券已领完");
        }
        sysBizCoupon.setIssueNum(sysBizCoupon.getIssueNum() + 1);
        sysBizCoupon.setSurplusNum(sysBizCoupon.getSurplusNum() - 1);
        sysBizCouponMapper.updateSysBizCoupon(sysBizCoupon);
        if (sysBizCouponReceive == null) {
            sysBizCouponReceive = createCouponReceiveRecord(sysBizUser, sysBizCouponGrant, sysBizCoupon);
        }
        if(sysBizCoupon.getNewCoupon()==1){
            sysBizCouponReceive.setNewCoupon(1);
        }
        sysBizCouponReceiveMapper.insert(sysBizCouponReceive);
        return sysBizCouponReceive;
    }

    private SysBizCouponReceive createCouponReceiveRecord(SysBizUser sysBizUser, SysBizCouponGrant sysBizCouponGrant, SysBizCoupon sysBizCoupon) {
        SysBizCouponReceive sysBizCouponReceive = new SysBizCouponReceive();
        BeanUtils.copyProperties(sysBizCouponGrant, sysBizCouponReceive);
        sysBizCouponReceive.setId(null);
        sysBizCouponReceive.setSourceType(0);
        sysBizCouponReceive.setCouponId(sysBizCoupon.getId());
        sysBizCouponReceive.setUserId(sysBizUser.getId());
        sysBizCouponReceive.setUserName(sysBizUser.getNickName());
        sysBizCouponReceive.setPhone(sysBizUser.getUserPhone());
        sysBizCouponReceive.setCouponName(sysBizCoupon.getName());
        sysBizCouponReceive.setReceiveTime(DateUtils.getNowDate());
        sysBizCouponReceive.setScopeUse(sysBizCoupon.getScopeUse());
        sysBizCouponReceive.setClassId(sysBizCoupon.getClassId());
        calculateExpiration(sysBizCouponReceive);
        return sysBizCouponReceive;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysBizCouponReceive createCouponReceiveRecord(SysBizUser sysBizUser, SysBizCoupon sysBizCoupon,Integer sourceType) throws Exception {
        SysBizCouponReceive sysBizCouponReceive = new SysBizCouponReceive();
        BeanUtils.copyProperties(sysBizCoupon, sysBizCouponReceive);
        sysBizCouponReceive.setTenantId(sysBizUser.getTenantId());
        sysBizCouponReceive.setSourceType(sourceType);
        sysBizCouponReceive.setId(null);
        sysBizCouponReceive.setCouponId(sysBizCoupon.getId());
        sysBizCouponReceive.setUserId(sysBizUser.getId());
        sysBizCouponReceive.setUserName(sysBizUser.getNickName());
        sysBizCouponReceive.setPhone(sysBizUser.getUserPhone());
        sysBizCouponReceive.setCouponName(sysBizCoupon.getName());
        sysBizCouponReceive.setReceiveTime(DateUtils.getNowDate());
        sysBizCouponReceive.setScopeUse(sysBizCoupon.getScopeUse());

        calculateExpiration(sysBizCouponReceive);

        // 查询优惠券的商品
        List<SysBizCouponGoods> sysBizCouponGoodsList = getCouponGoodsByCouponId(sysBizCoupon.getId());
        // 更新优惠券状态（使用事务保证数据一致性）
        updateCouponAndInsertReceiveRecord(sysBizCoupon, sysBizUser, sysBizCouponReceive, null);

        insertCouponGoodsUserRecords(sysBizUser, sysBizCouponReceive.getId(), sysBizCouponGoodsList);
        return sysBizCouponReceive;
    }

    private void calculateExpiration(SysBizCouponReceive sysBizCouponReceive) {
        // 计算优惠券过期时间
        if (sysBizCouponReceive.getValidityType() == 2) {
            String date = DateUtils.getDate();
            Date beginTime = DateUtils.addDays(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, date + " 00:00:00"), Math.toIntExact(sysBizCouponReceive.getReceivingDay()));
            sysBizCouponReceive.setTermBeginTime(beginTime);
            Date endTime = DateUtils.addDays(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, date + " 23:59:59"), Math.toIntExact(sysBizCouponReceive.getReceivingDay() + sysBizCouponReceive.getEffectiveDay()));
            sysBizCouponReceive.setTermEndTime(endTime);
        } else {
            String date = DateUtils.dateTime(sysBizCouponReceive.getTermEndTime());
            sysBizCouponReceive.setTermEndTime(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, date + " 23:59:59"));
        }
    }

    private void insertCouponGoodsUserRecords(SysBizUser sysBizUser, Long receiveId, List<SysBizCouponGoods> sysBizCouponGoodsList) {
        // 如果有指定商品，插入用户优惠券商品关联表
        if (sysBizCouponGoodsList.isEmpty()) {
            return;
        }
        List<SysBizCouponGoodsUser> sysBizCouponGoodsUserList = sysBizCouponGoodsList.stream().map(goods -> {
            SysBizCouponGoodsUser userRecord = new SysBizCouponGoodsUser();
            userRecord.setUserId(sysBizUser.getId());
            userRecord.setTenantId(sysBizUser.getTenantId());
            userRecord.setReceiveId(receiveId);
            userRecord.setGoodsId(goods.getGoodsId());
            return userRecord;
        }).collect(Collectors.toList());
        sysBizCouponGoodsUserService.saveBatch(sysBizCouponGoodsUserList);
    }


    /**
     * 修改优惠券发放
     *
     * @param sysBizCouponGrant 优惠券发放
     * @return 结果
     */
    @Override
    public int updateSysBizCouponGrant(SysBizCouponGrant sysBizCouponGrant) {
        sysBizCouponGrant.setUpdateTime(DateUtils.getNowDate());
        return sysBizCouponGrantMapper.updateById(sysBizCouponGrant);
    }

    /**
     * 批量删除优惠券发放
     *
     * @param ids 需要删除的优惠券发放主键
     * @return 结果
     */
    @Override
    public int deleteSysBizCouponGrantByIds(Long[] ids) {
        return sysBizCouponGrantMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除优惠券发放信息
     *
     * @param id 优惠券发放主键
     * @return 结果
     */
    @Override
    public int deleteSysBizCouponGrantById(Long id) {
        return sysBizCouponGrantMapper.deleteById(id);
    }
}
